package unimelb.filesync.client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import unimelb.filesync.client.protocol.ConnectToServerPhase;
import unimelb.filesync.client.protocol.CreateSecretKeyAndInitVectorPhase;
import unimelb.filesync.client.protocol.GetPublicKeyPhase;
import unimelb.filesync.client.protocol.PrepareClientFileSync;
import unimelb.filesync.client.protocol.RequestBlockSizePhase;
import unimelb.filesync.client.protocol.SendPasswordPhase;
import unimelb.filesync.client.protocol.SendSecretKeyPhase;
import unimelb.filesync.common.FileSyncApp;
import unimelb.filesync.common.misc.ArgsValidator;
import unimelb.filesync.common.misc.ProtocolContext;
import unimelb.filesync.common.protocol.IFileSyncPhase;
import unimelb.filesync.common.protocol.ReadPasswordInput;

public class FileSyncClient extends FileSyncApp {

    @Override
    protected Map<String, Object> toParamMap(String[] args) {
        if (args.length != 5) {
            throw new IllegalArgumentException("Invalid arguments. Usage: java -jar syncclient.jar filename host port role blocksize");
        }
        final ArgsValidator validator = new ArgsValidator();
        validator.validatePort(args[2]);
        validator.validateBlockSize(args[4]);
        if (!ProtocolContext.ROLE_SOURCE.equalsIgnoreCase(args[3]) && !ProtocolContext.ROLE_DESTINATION.equalsIgnoreCase(args[3])) {
            throw new IllegalArgumentException("Role must either be source or destination");
        }

        final Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(ProtocolContext.FILE_NAME, args[0]);
        paramMap.put(ProtocolContext.HOST, args[1]);
        paramMap.put(ProtocolContext.PORT, Integer.valueOf(args[2]));
        paramMap.put(ProtocolContext.ROLE, args[3]);
        paramMap.put(ProtocolContext.BLOCK_SIZE, Long.valueOf(args[4]));
        return paramMap;
    }

    @Override
    protected ProtocolContext getProtocolContext() {
        return ProtocolContext.Client;
    }

    @Override
    protected List<IFileSyncPhase> createPhaseList() {
        final List<IFileSyncPhase> phases = new ArrayList<IFileSyncPhase>();
        
        phases.add(new ReadPasswordInput(getProtocolContext()));
        phases.add(new CreateSecretKeyAndInitVectorPhase(getProtocolContext()));
        
        phases.add(new ConnectToServerPhase(getProtocolContext()));
        
        phases.add(new GetPublicKeyPhase(getProtocolContext()));
        phases.add(new SendSecretKeyPhase(getProtocolContext()));
        phases.add(new SendPasswordPhase(getProtocolContext()));
        
        phases.add(new RequestBlockSizePhase(getProtocolContext()));
        phases.add(new PrepareClientFileSync(getProtocolContext()));
        return phases;
    }

    public static void main(String[] args) {
        try {
            System.out.println("Client is running");
            new FileSyncClient().run(args);
        } catch (Exception e) {
            System.out.println("Exception occurred");
            e.printStackTrace();
            System.exit(1);
        }
    }

}
